/*
 * Copyright (c) 2024 Black Sesame Technologies
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 * http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */

#include <cstdlib>
#include "dds/ddsrt/time.h"
#include "dal_cyclonedds/converter/QosConverter.hpp"
#include "dal_cyclonedds/utils/StringUtils.hpp"
#include "dal_cyclonedds/utils/log.hpp"
#include "dal/config_loader.h"

static void SetDomainParticipantQosPresent(dds_qos_t* qos)
{
    // qos->present |= QP_USER_DATA;
}

static void SetTopicQosPresent(dds_qos_t* qos)
{
    qos->present |= QP_TOPIC_DATA | QP_DURABILITY | QP_DURABILITY_SERVICE | QP_DEADLINE |
                    QP_LATENCY_BUDGET | QP_LIVELINESS | QP_RELIABILITY | QP_DESTINATION_ORDER |
                    QP_HISTORY | QP_RESOURCE_LIMITS | QP_TRANSPORT_PRIORITY | QP_LIFESPAN |
                    QP_OWNERSHIP;
}

static void SetPubSubQosPresent(dds_qos_t* qos)
{
    qos->present |= QP_PRESENTATION;
}

static void SetDataWriterQosPresent(dds_qos_t* qos)
{
    qos->present |= QP_DURABILITY | QP_DURABILITY_SERVICE | QP_DEADLINE | QP_LATENCY_BUDGET |
                    QP_LIVELINESS | QP_RELIABILITY | QP_DESTINATION_ORDER | QP_HISTORY |
                    QP_RESOURCE_LIMITS | QP_TRANSPORT_PRIORITY | QP_LIFESPAN |
                    // QP_USER_DATA |   // TODO!: enable USER_DATA present will cause cyberRT
                    // manager write fail.
                    QP_OWNERSHIP | QP_OWNERSHIP_STRENGTH | QP_ADLINK_WRITER_DATA_LIFECYCLE;
}
static void SetDataReaderQosPresent(dds_qos_t* qos)
{
    qos->present |= QP_DURABILITY | QP_DEADLINE | QP_LATENCY_BUDGET | QP_LIVELINESS |
                    QP_RELIABILITY | QP_DESTINATION_ORDER | QP_HISTORY | QP_RESOURCE_LIMITS |
                    // QP_USER_DATA |    // TODO!: enable USER_DATA present will cause cyberRT
                    // manager write fail.
                    QP_OWNERSHIP | QP_TIME_BASED_FILTER | QP_ADLINK_READER_DATA_LIFECYCLE;
}

static bool exceedsMaxNanoseconds(const dal_duration_t& dur)
{
    constexpr int64_t MAX_SEC = INT64_MAX / 1000000000;
    constexpr uint64_t MAX_NANOSEC = INT64_MAX % 1000000000;

    if (dur.sec > MAX_SEC) {
        return true;
    }

    else if (dur.sec == MAX_SEC && dur.nanosec > MAX_NANOSEC) {
        return true;
    }

    return false;
}

static dds_duration_t ConvertTimeDurtaitonFromDalToCyclonedds(const dal_duration_t& dur)
{
    if (dur.sec > DAL_INFINITE_SECONDS)
        return __INT64_MAX__;

    if (exceedsMaxNanoseconds(dur)) {
        return __INT64_MAX__;
    }

    if (dur.sec == DAL_INFINITE_SECONDS && dur.nanosec == DAL_INFINITE_NANOSECONDS) {
        return __INT64_MAX__;
    }

    return DDS_SECS(dur.sec) + dur.nanosec;
}

QosConverter* QosConverter::singleton_ = nullptr;

QosConverter::QosConverter() {}

QosConverter* QosConverter::GetInstance()
{
    if (singleton_ == nullptr) {
        singleton_ = new QosConverter();
    }
    return singleton_;
}

dal_ret_t QosConverter::SetUnicastToCycloneddsParticipantQos(dal_domain_participant_qos_t* d_qos,
                                                             std::string& config_str)
{
    if (d_qos == nullptr) {
        LOG_ERROR_WITH_LOCATION() << "Invaild params: " << LOG_ENDL;
        return DAL_RETCODE_ERROR;
    }
    auto seq = &d_qos->unicast_locator_seq;

    std::string expand_env_prefix = "";
    if (!getenv("CYCLONEDDS_URI")) {
        expand_env_prefix = "${CYCLONEDDS_URI}${CYCLONEDDS_URI:+,}";
    }

    if (d_qos->localhost_only == DAL_TRUE) {
        config_str = expand_env_prefix + "<General><Interfaces><NetworkInterface "
                                         "address=\"127.0.0.1\" /></Interfaces></General>";
        return DAL_RETCODE_OK;
    }

    uint32_t unicast_locator_num = SIZE_SEQUENCE(dal_locator_t, seq);
    if (unicast_locator_num == 0)
        return DAL_RETCODE_OK;

    config_str = expand_env_prefix + "<Discovery><Peers>";
    dal_locator_t* d_locator = (dal_locator_t*)calloc(sizeof(dal_locator_t), 1);
    for (int i = 0; i < unicast_locator_num; i++) {
        memset(d_locator, 0, sizeof(dal_locator_t));
        GET_ELEMENT_SEQUENCE(dal_locator_t, seq, i, d_locator);
        auto ip_str = std::string((const char*)(d_locator->address),
                                  GetStringLengthInByteArray(d_locator->address));
        auto ips = Split(ip_str, '.');
        if (ips.size() != 4) {
            LOG_ERROR_WITH_LOCATION() << "unicast_locator invalid address: " << ip_str << LOG_ENDL;
            config_str.clear();
            free(d_locator);
            return DAL_RETCODE_BAD_PARAMETER;
        }

        if (ip_str.compare("127.0.0.1") == 0) {
            continue;
        }
        config_str.append("<Peer address=\"" + ip_str + "\" />");
    }
    config_str.append("</Peers></Discovery>");

    free(d_locator);
    return DAL_RETCODE_OK;
}

dal_ret_t QosConverter::SetMulticastToCycloneddsParticipantQos(dal_domain_participant_qos_t* d_qos,
                                                               std::string& config_str)
{
    if (d_qos == nullptr) {
        LOG_ERROR_WITH_LOCATION() << "Invaild params: " << LOG_ENDL;
        return DAL_RETCODE_ERROR;
    }
    auto seq = &d_qos->multicast_locator_seq;

    std::string expand_env_prefix = "";
    if (!getenv("CYCLONEDDS_URI")) {
        expand_env_prefix = "${CYCLONEDDS_URI}${CYCLONEDDS_URI:+,}";
    }

    // only allow multicast used in spdp.
    config_str = expand_env_prefix + "<General><AllowMulticast>spdp</AllowMulticast></General>";
    uint32_t multicast_locator_num = SIZE_SEQUENCE(dal_locator_t, seq);
    if (multicast_locator_num == 0) {
        // cyclone will set default multicast 239.255.0.1
        return DAL_RETCODE_OK;
    }

    dal_locator_t* d_locator = (dal_locator_t*)calloc(sizeof(dal_locator_t), 1);
    if (d_locator == nullptr) {
        LOG_ERROR_WITH_LOCATION() << "calloc dal_locator_t failed: " << LOG_ENDL;
        config_str.clear();
        return DAL_RETCODE_ERROR;
    }
    config_str.append("<Discovery><Peers>");
    for (int i = 0; i < multicast_locator_num; i++) {
        memset(d_locator, 0, sizeof(dal_locator_t));
        GET_ELEMENT_SEQUENCE(dal_locator_t, seq, i, d_locator);
        std::string ip_str = std::string((const char*)(d_locator->address),
                                         GetStringLengthInByteArray(d_locator->address));
        auto ips = Split(ip_str, '.');
        if (ips.size() != 4) {
            LOG_ERROR_WITH_LOCATION()
                << "multicast_locator invalid address: " << ip_str << LOG_ENDL;
            config_str.clear();
            free(d_locator);
            return DAL_RETCODE_BAD_PARAMETER;
        }
        config_str.append("<Peer address=\"" + ip_str + "\" />");
    }
    config_str.append("</Peers></Discovery>");

    free(d_locator);
    return DAL_RETCODE_OK;
}

dal_ret_t
QosConverter::ConvertParticipantQosFromDalToCyclonedds(dal_domain_participant_qos_t* d_qos,
                                                       dds_qos_t* c_qos)
{
    if (c_qos == nullptr) {
        LOG_ERROR_WITH_LOCATION() << "cyclonedds qos is NULL" << LOG_ENDL;
        return DAL_RETCODE_ERROR;
    }
    if (d_qos == DAL_PARTICIPANT_QOS_DEFAULT) {
        return DAL_RETCODE_OK;
    }

    int seq_size = SIZE_SEQUENCE(octet, &d_qos->user_data.value);
    if (0l != seq_size) {
        c_qos->user_data.length = seq_size;
        c_qos->user_data.value = (uint8_t*)malloc(c_qos->user_data.length);
        for (int i = 0; i < seq_size; i++) {
            uint8_t val = 0;
            GET_ELEMENT_SEQUENCE(octet, &d_qos->user_data.value, i, &val);
            memcpy(c_qos->user_data.value + i, &val, sizeof(uint8_t));
        }
    }

    c_qos->entity_factory.autoenable_created_entities =
        d_qos->entity_factory.autoenable_created_entities;

    if (d_qos->participant_name) {
        dds_qset_entity_name(c_qos, d_qos->participant_name);
    }
    SetDomainParticipantQosPresent(c_qos);
    return DAL_RETCODE_OK;
}

dal_ret_t QosConverter::ConvertPublisherQosFromDalToCyclonedds(dal_publisher_qos_t* d_qos,
                                                               dds_qos_t* c_qos)
{
    if (c_qos == nullptr) {
        LOG_ERROR_WITH_LOCATION() << "cyclonedds qos is NULL" << LOG_ENDL;
        return DAL_RETCODE_ERROR;
    }
    if (d_qos == DAL_PUBLISHER_QOS_DEFAULT) {
        dds_copy_qos(c_qos, &ddsi_default_qos_publisher_subscriber);
        return DAL_RETCODE_OK;
    }

    switch (d_qos->presentation.access_scope) {
        default:
        case DAL_INSTANCE_PRESENTATION_QOS:
            c_qos->presentation.access_scope = DDS_PRESENTATION_INSTANCE;
            break;
        case DAL_TOPIC_PRESENTATION_QOS:
            c_qos->presentation.access_scope = DDS_PRESENTATION_TOPIC;
            break;
        case DAL_GROUP_PRESENTATION_QOS:
            c_qos->presentation.access_scope = DDS_PRESENTATION_GROUP;
            break;
    }
    c_qos->presentation.coherent_access = d_qos->presentation.coherent_access;
    c_qos->presentation.ordered_access = d_qos->presentation.ordered_access;

    c_qos->entity_factory.autoenable_created_entities =
        d_qos->entity_factory.autoenable_created_entities;

    int seq_size = SIZE_SEQUENCE(octet, &d_qos->group_data.value);
    if (0l != seq_size) {
        c_qos->group_data.length = seq_size;
        c_qos->group_data.value = (uint8_t*)malloc(c_qos->group_data.length);
        for (int i = 0; i < seq_size; i++) {
            uint8_t val = 0;
            GET_ELEMENT_SEQUENCE(octet, &d_qos->group_data.value, i, &val);
            memcpy(c_qos->group_data.value + i, &val, sizeof(uint8_t));
        }
        c_qos->present |= QP_GROUP_DATA;
    }

    if (d_qos->partition.name.n > 0 && d_qos->partition.name.strs) {
        dds_qset_partition(
            c_qos, d_qos->partition.name.n, (const char**)d_qos->partition.name.strs);
    }

    SetPubSubQosPresent(c_qos);
    return DAL_RETCODE_OK;
}

dal_ret_t QosConverter::ConvertSubscriberQosFromDalToCyclonedds(dal_subscriber_qos_t* d_qos,
                                                                dds_qos_t* c_qos)
{
    if (c_qos == nullptr) {
        LOG_ERROR_WITH_LOCATION() << "cyclonedds qos is NULL" << LOG_ENDL;
        return DAL_RETCODE_ERROR;
    }
    if (d_qos == DAL_SUBSCRIBER_QOS_DEFAULT) {
        dds_copy_qos(c_qos, &ddsi_default_qos_publisher_subscriber);
        return DAL_RETCODE_OK;
    }

    switch (d_qos->presentation.access_scope) {
        default:
        case DAL_INSTANCE_PRESENTATION_QOS:
            c_qos->presentation.access_scope = DDS_PRESENTATION_INSTANCE;
            break;
        case DAL_TOPIC_PRESENTATION_QOS:
            c_qos->presentation.access_scope = DDS_PRESENTATION_TOPIC;
            break;
        case DAL_GROUP_PRESENTATION_QOS:
            c_qos->presentation.access_scope = DDS_PRESENTATION_GROUP;
            break;
    }
    c_qos->presentation.coherent_access = d_qos->presentation.coherent_access;
    c_qos->presentation.ordered_access = d_qos->presentation.ordered_access;

    c_qos->entity_factory.autoenable_created_entities =
        d_qos->entity_factory.autoenable_created_entities;

    int seq_size = SIZE_SEQUENCE(octet, &d_qos->group_data.value);
    if (0l != seq_size) {
        c_qos->group_data.length = seq_size;
        c_qos->group_data.value = (uint8_t*)malloc(c_qos->group_data.length);
        for (int i = 0; i < seq_size; i++) {
            uint8_t val = 0;
            GET_ELEMENT_SEQUENCE(octet, &d_qos->group_data.value, i, &val);
            memcpy(c_qos->group_data.value + i, &val, sizeof(uint8_t));
        }
        c_qos->present |= QP_GROUP_DATA;
    }

    if (d_qos->partition.name.n > 0 && d_qos->partition.name.strs) {
        dds_qset_partition(
            c_qos, d_qos->partition.name.n, (const char**)d_qos->partition.name.strs);
    }

    SetPubSubQosPresent(c_qos);
    return DAL_RETCODE_OK;
}

dal_ret_t QosConverter::ConvertTopicQosFromDalToCyclonedds(dal_topic_qos_t* d_qos, dds_qos_t* c_qos)
{
    if (c_qos == nullptr) {
        LOG_ERROR_WITH_LOCATION() << "cyclonedds qos is NULL" << LOG_ENDL;
        return DAL_RETCODE_ERROR;
    }
    if (d_qos == DAL_TOPIC_QOS_DEFAULT) {
        dds_copy_qos(c_qos, &ddsi_default_qos_topic);
        return DAL_RETCODE_OK;
    }
    int seq_size = SIZE_SEQUENCE(octet, &d_qos->topic_data.value);
    if (0l != seq_size) {
        c_qos->topic_data.length = seq_size;
        c_qos->topic_data.value = (uint8_t*)malloc(c_qos->topic_data.length);
        for (int i = 0; i < seq_size; i++) {
            uint8_t val = 0;
            GET_ELEMENT_SEQUENCE(octet, &d_qos->topic_data.value, i, &val);
            memcpy(c_qos->topic_data.value + i, &val, sizeof(uint8_t));
        }
    }

    switch (d_qos->history.kind) {
        default:
        case DAL_KEEP_LAST_HISTORY_QOS:
            c_qos->history.kind = DDS_HISTORY_KEEP_LAST;
            break;
        case DAL_KEEP_ALL_HISTORY_QOS:
            c_qos->history.kind = DDS_HISTORY_KEEP_ALL;
            break;
    }
    c_qos->history.depth = d_qos->history.depth;
    c_qos->present |= QP_HISTORY;

    c_qos->durability_service.service_cleanup_delay =
        ConvertTimeDurtaitonFromDalToCyclonedds(d_qos->durability_service.service_cleanup_delay);

    switch (d_qos->durability_service.history_kind) {
        default:
        case DAL_KEEP_LAST_HISTORY_QOS:
            c_qos->durability_service.history.kind = DDS_HISTORY_KEEP_LAST;
            break;
        case DAL_KEEP_ALL_HISTORY_QOS:
            c_qos->durability_service.history.kind = DDS_HISTORY_KEEP_ALL;
            break;
    }
    c_qos->durability_service.history.depth = d_qos->durability_service.history_depth;
    c_qos->durability_service.resource_limits.max_samples = d_qos->durability_service.max_samples;
    c_qos->durability_service.resource_limits.max_instances =
        d_qos->durability_service.max_instances;
    c_qos->durability_service.resource_limits.max_samples_per_instance =
        d_qos->durability_service.max_samples_per_instance;

    switch (d_qos->durability.kind) {
        default:
        case DAL_VOLATILE_DURABILITY_QOS:
            c_qos->durability.kind = DDS_DURABILITY_VOLATILE;
            break;
        case DAL_TRANSIENT_LOCAL_DURABILITY_QOS:
            c_qos->durability.kind = DDS_DURABILITY_TRANSIENT_LOCAL;
            break;
        case DAL_TRANSIENT_DURABILITY_QOS:
            c_qos->durability.kind = DDS_DURABILITY_TRANSIENT;
            break;
        case DAL_PERSISTENT_DURABILITY_QOS:
            c_qos->durability.kind = DDS_DURABILITY_PERSISTENT;
            break;
    }

    c_qos->deadline.deadline = ConvertTimeDurtaitonFromDalToCyclonedds(d_qos->deadline.period);

    c_qos->latency_budget.duration =
        ConvertTimeDurtaitonFromDalToCyclonedds(d_qos->latency_budget.duration);

    switch (d_qos->liveliness.kind) {
        default:
        case DAL_AUTOMATIC_LIVELINESS_QOS:
            c_qos->liveliness.kind = DDS_LIVELINESS_AUTOMATIC;
            break;
        case DAL_MANUAL_BY_PARTICIPANT_LIVELINESS_QOS:
            c_qos->liveliness.kind = DDS_LIVELINESS_MANUAL_BY_PARTICIPANT;
            break;
        case DAL_MANUAL_BY_TOPIC_LIVELINESS_QOS:
            c_qos->liveliness.kind = DDS_LIVELINESS_MANUAL_BY_TOPIC;
            break;
    }

    c_qos->liveliness.lease_duration =
        ConvertTimeDurtaitonFromDalToCyclonedds(d_qos->liveliness.lease_duration);

    switch (d_qos->reliability.kind) {
        default:
        case DAL_BEST_EFFORT_RELIABILITY_QOS:
            c_qos->reliability.kind = DDS_RELIABILITY_BEST_EFFORT;
            break;
        case DAL_RELIABLE_RELIABILITY_QOS:
            c_qos->reliability.kind = DDS_RELIABILITY_RELIABLE;
            break;
    }
    c_qos->reliability.max_blocking_time =
        ConvertTimeDurtaitonFromDalToCyclonedds(d_qos->reliability.max_blocking_time);

    switch (d_qos->destination_order.kind) {
        default:
        case DAL_BY_RECEPTION_TIMESTAMP_DESTINATIONORDER_QOS:
            c_qos->destination_order.kind = DDS_DESTINATIONORDER_BY_RECEPTION_TIMESTAMP;
            break;
        case DAL_BY_SOURCE_TIMESTAMP_DESTINATIONORDER_QOS:
            c_qos->destination_order.kind = DDS_DESTINATIONORDER_BY_SOURCE_TIMESTAMP;
            break;
    }

    c_qos->resource_limits.max_samples = d_qos->resource_limits.max_samples;
    c_qos->resource_limits.max_instances = d_qos->resource_limits.max_instances;
    c_qos->resource_limits.max_samples_per_instance =
        d_qos->resource_limits.max_samples_per_instance;

    c_qos->transport_priority.value = d_qos->transport_priority.value;

    c_qos->lifespan.duration = ConvertTimeDurtaitonFromDalToCyclonedds(d_qos->lifespan.duration);

    switch (d_qos->ownership.kind) {
        default:
        case DAL_SHARED_OWNERSHIP_QOS:
            c_qos->ownership.kind = DDS_OWNERSHIP_SHARED;
            break;
        case DAL_EXCLUSIVE_OWNERSHIP_QOS:
            c_qos->ownership.kind = DDS_OWNERSHIP_EXCLUSIVE;
            break;
    }

    SetTopicQosPresent(c_qos);
    return DAL_RETCODE_OK;
}

dal_ret_t QosConverter::ConvertDataWriterQosFromDalToCyclonedds(dal_datawriter_qos_t* d_qos,
                                                                dds_qos_t* c_qos)
{
    if (c_qos == nullptr) {
        LOG_ERROR_WITH_LOCATION() << "cyclonedds qos is NULL" << LOG_ENDL;
        return DAL_RETCODE_ERROR;
    }
    if (d_qos == DAL_DATAWRITER_QOS_DEFAULT) {
        dds_copy_qos(c_qos, &ddsi_default_qos_writer);
        return DAL_RETCODE_OK;
    }

    c_qos->present |= QP_TIME_BASED_FILTER;

    switch (d_qos->history.kind) {
        default:
        case DAL_KEEP_LAST_HISTORY_QOS:
            c_qos->history.kind = DDS_HISTORY_KEEP_LAST;
            break;
        case DAL_KEEP_ALL_HISTORY_QOS:
            c_qos->history.kind = DDS_HISTORY_KEEP_ALL;
            break;
    }
    c_qos->history.depth = d_qos->history.depth;
    c_qos->present |= QP_HISTORY;

    c_qos->durability_service.service_cleanup_delay =
        ConvertTimeDurtaitonFromDalToCyclonedds(d_qos->durability_service.service_cleanup_delay);
    switch (d_qos->durability_service.history_kind) {
        default:
        case DAL_KEEP_LAST_HISTORY_QOS:
            c_qos->durability_service.history.kind = DDS_HISTORY_KEEP_LAST;
            break;
        case DAL_KEEP_ALL_HISTORY_QOS:
            c_qos->durability_service.history.kind = DDS_HISTORY_KEEP_ALL;
            break;
    }
    c_qos->durability_service.history.depth = d_qos->durability_service.history_depth;
    c_qos->durability_service.resource_limits.max_samples = d_qos->durability_service.max_samples;
    c_qos->durability_service.resource_limits.max_instances =
        d_qos->durability_service.max_instances;
    c_qos->durability_service.resource_limits.max_samples_per_instance =
        d_qos->durability_service.max_samples_per_instance;

    switch (d_qos->durability.kind) {
        default:
        case DAL_VOLATILE_DURABILITY_QOS:
            dds_qset_durability(c_qos, DDS_DURABILITY_VOLATILE);
            break;
        case DAL_TRANSIENT_LOCAL_DURABILITY_QOS:
            dds_history_kind_t hk;
            int32_t hd;
            dds_qget_history(c_qos, &hk, &hd);
            dds_qset_durability(c_qos, DDS_DURABILITY_TRANSIENT_LOCAL);
            dds_qset_durability_service(c_qos,
                                        DDS_SECS(0),
                                        hk,
                                        hd,
                                        DDS_LENGTH_UNLIMITED,
                                        DDS_LENGTH_UNLIMITED,
                                        DDS_LENGTH_UNLIMITED);
            break;
        case DAL_TRANSIENT_DURABILITY_QOS:
            c_qos->durability.kind = DDS_DURABILITY_TRANSIENT;
            break;
        case DAL_PERSISTENT_DURABILITY_QOS:
            c_qos->durability.kind = DDS_DURABILITY_PERSISTENT;
            break;
    }

    c_qos->deadline.deadline =
        ConvertTimeDurtaitonFromDalToCyclonedds(d_qos->deadline.period);  // DDS_INFINITY

    c_qos->latency_budget.duration =
        ConvertTimeDurtaitonFromDalToCyclonedds(d_qos->latency_budget.duration);

    switch (d_qos->liveliness.kind) {
        default:
        case DAL_AUTOMATIC_LIVELINESS_QOS:
            c_qos->liveliness.kind = DDS_LIVELINESS_AUTOMATIC;
            break;
        case DAL_MANUAL_BY_PARTICIPANT_LIVELINESS_QOS:
            c_qos->liveliness.kind = DDS_LIVELINESS_MANUAL_BY_PARTICIPANT;
            break;
        case DAL_MANUAL_BY_TOPIC_LIVELINESS_QOS:
            c_qos->liveliness.kind = DDS_LIVELINESS_MANUAL_BY_TOPIC;
            break;
    }

    c_qos->liveliness.lease_duration =
        ConvertTimeDurtaitonFromDalToCyclonedds(d_qos->liveliness.lease_duration);  // DDS_INFINITY;

    switch (d_qos->reliability.kind) {
        default:
        case DAL_RELIABLE_RELIABILITY_QOS:
            c_qos->reliability.kind = DDS_RELIABILITY_RELIABLE;
            break;
        case DAL_BEST_EFFORT_RELIABILITY_QOS:
            c_qos->reliability.kind = DDS_RELIABILITY_BEST_EFFORT;
            break;
    }
    c_qos->reliability.max_blocking_time =
        ConvertTimeDurtaitonFromDalToCyclonedds(d_qos->reliability.max_blocking_time);

    switch (d_qos->destination_order.kind) {
        default:
        case DAL_BY_RECEPTION_TIMESTAMP_DESTINATIONORDER_QOS:
            c_qos->destination_order.kind = DDS_DESTINATIONORDER_BY_RECEPTION_TIMESTAMP;
            break;
        case DAL_BY_SOURCE_TIMESTAMP_DESTINATIONORDER_QOS:
            c_qos->destination_order.kind = DDS_DESTINATIONORDER_BY_SOURCE_TIMESTAMP;
            break;
    }

    c_qos->resource_limits.max_samples = d_qos->resource_limits.max_samples;
    c_qos->resource_limits.max_instances = d_qos->resource_limits.max_instances;
    c_qos->resource_limits.max_samples_per_instance =
        d_qos->resource_limits.max_samples_per_instance;

    c_qos->transport_priority.value = d_qos->transport_priority.value;

    c_qos->lifespan.duration =
        ConvertTimeDurtaitonFromDalToCyclonedds(d_qos->lifespan.duration);  // DDS_INFINITY;

    int seq_size = SIZE_SEQUENCE(octet, &d_qos->user_data.value);
    if (seq_size > 0) {
        uint8_t* user_data_value = new uint8_t[seq_size]();
        for (int i = 0; i < seq_size; i++) {
            uint8_t val = 0;
            GET_ELEMENT_SEQUENCE(octet, &d_qos->user_data.value, i, &val);
            memcpy(user_data_value + i, &val, sizeof(uint8_t));
        }
        dds_qset_userdata(c_qos, user_data_value, seq_size);
        delete[] user_data_value;
    }

    switch (d_qos->ownership.kind) {
        default:
        case DAL_SHARED_OWNERSHIP_QOS:
            c_qos->ownership.kind = DDS_OWNERSHIP_SHARED;
            break;
        case DAL_EXCLUSIVE_OWNERSHIP_QOS:
            c_qos->ownership.kind = DDS_OWNERSHIP_EXCLUSIVE;
            break;
    }

    c_qos->ownership_strength.value = d_qos->ownership_strength.value;

    c_qos->writer_data_lifecycle.autodispose_unregistered_instances =
        d_qos->writer_data_lifecycle.autodispose_unregistered_instances;

    SetDataWriterQosPresent(c_qos);
    return DAL_RETCODE_OK;
}

dal_ret_t QosConverter::ConvertDataReaderQosFromDalToCyclonedds(dal_datareader_qos_t* d_qos,
                                                                dds_qos_t* c_qos)
{
    if (c_qos == nullptr) {
        LOG_ERROR_WITH_LOCATION() << "cyclonedds qos is NULL" << LOG_ENDL;
        return DAL_RETCODE_ERROR;
    }
    if (d_qos == DAL_DATAREADER_QOS_DEFAULT) {
        dds_copy_qos(c_qos, &ddsi_default_qos_reader);
        return DAL_RETCODE_OK;
    }
    // c_qos->present |= QP_TIME_BASED_FILTER;

    switch (d_qos->history.kind) {
        default:
        case DAL_KEEP_LAST_HISTORY_QOS:
            c_qos->history.kind = DDS_HISTORY_KEEP_LAST;
            break;
        case DAL_KEEP_ALL_HISTORY_QOS:
            c_qos->history.kind = DDS_HISTORY_KEEP_ALL;
            break;
    }
    c_qos->history.depth = d_qos->history.depth;
    c_qos->present |= QP_HISTORY;

    switch (d_qos->durability.kind) {
        default:
        case DAL_VOLATILE_DURABILITY_QOS:
            dds_qset_durability(c_qos, DDS_DURABILITY_VOLATILE);
            break;
        case DAL_TRANSIENT_LOCAL_DURABILITY_QOS:
            dds_history_kind_t hk;
            int32_t hd;
            dds_qget_history(c_qos, &hk, &hd);
            dds_qset_durability(c_qos, DDS_DURABILITY_TRANSIENT_LOCAL);
            dds_qset_durability_service(c_qos,
                                        DDS_SECS(0),
                                        hk,
                                        hd,
                                        DDS_LENGTH_UNLIMITED,
                                        DDS_LENGTH_UNLIMITED,
                                        DDS_LENGTH_UNLIMITED);
            break;
        case DAL_TRANSIENT_DURABILITY_QOS:
            c_qos->durability.kind = DDS_DURABILITY_TRANSIENT;
            break;
        case DAL_PERSISTENT_DURABILITY_QOS:
            c_qos->durability.kind = DDS_DURABILITY_PERSISTENT;
            break;
    }

    c_qos->deadline.deadline =
        ConvertTimeDurtaitonFromDalToCyclonedds(d_qos->deadline.period);  // DDS_INFINITY;

    c_qos->latency_budget.duration =
        ConvertTimeDurtaitonFromDalToCyclonedds(d_qos->latency_budget.duration);

    switch (d_qos->liveliness.kind) {
        default:
        case DAL_AUTOMATIC_LIVELINESS_QOS:
            c_qos->liveliness.kind = DDS_LIVELINESS_AUTOMATIC;
            break;
        case DAL_MANUAL_BY_PARTICIPANT_LIVELINESS_QOS:
            c_qos->liveliness.kind = DDS_LIVELINESS_MANUAL_BY_PARTICIPANT;
            break;
        case DAL_MANUAL_BY_TOPIC_LIVELINESS_QOS:
            c_qos->liveliness.kind = DDS_LIVELINESS_MANUAL_BY_TOPIC;
            break;
    }
    c_qos->liveliness.lease_duration =
        ConvertTimeDurtaitonFromDalToCyclonedds(d_qos->liveliness.lease_duration);  // DDS_INFINITY;

    switch (d_qos->reliability.kind) {
        default:
        case DAL_RELIABLE_RELIABILITY_QOS:
            c_qos->reliability.kind = DDS_RELIABILITY_RELIABLE;
            break;
        case DAL_BEST_EFFORT_RELIABILITY_QOS:
            c_qos->reliability.kind = DDS_RELIABILITY_BEST_EFFORT;
            break;
    }
    c_qos->reliability.max_blocking_time =
        ConvertTimeDurtaitonFromDalToCyclonedds(d_qos->reliability.max_blocking_time);

    switch (d_qos->destination_order.kind) {
        default:
        case DAL_BY_RECEPTION_TIMESTAMP_DESTINATIONORDER_QOS:
            c_qos->destination_order.kind = DDS_DESTINATIONORDER_BY_RECEPTION_TIMESTAMP;
            break;
        case DAL_BY_SOURCE_TIMESTAMP_DESTINATIONORDER_QOS:
            c_qos->destination_order.kind = DDS_DESTINATIONORDER_BY_SOURCE_TIMESTAMP;
            break;
    }

    c_qos->resource_limits.max_samples = d_qos->resource_limits.max_samples;
    c_qos->resource_limits.max_instances = d_qos->resource_limits.max_instances;
    c_qos->resource_limits.max_samples_per_instance =
        d_qos->resource_limits.max_samples_per_instance;

    int seq_size = SIZE_SEQUENCE(octet, &d_qos->user_data.value);
    if (seq_size > 0) {
        uint8_t* user_data_value = new uint8_t[seq_size]();
        for (int i = 0; i < seq_size; i++) {
            uint8_t val = 0;
            GET_ELEMENT_SEQUENCE(octet, &d_qos->user_data.value, i, &val);
            memcpy(user_data_value + i, &val, sizeof(uint8_t));
        }
        dds_qset_userdata(c_qos, user_data_value, seq_size);
        delete[] user_data_value;
    }

    switch (d_qos->ownership.kind) {
        default:
        case DAL_SHARED_OWNERSHIP_QOS:
            c_qos->ownership.kind = DDS_OWNERSHIP_SHARED;
            break;
        case DAL_EXCLUSIVE_OWNERSHIP_QOS:
            c_qos->ownership.kind = DDS_OWNERSHIP_EXCLUSIVE;
            break;
    }

    c_qos->time_based_filter.minimum_separation =
        ConvertTimeDurtaitonFromDalToCyclonedds(d_qos->time_based_filter.minimum_separation);

    c_qos->reader_data_lifecycle.autopurge_nowriter_samples_delay =
        ConvertTimeDurtaitonFromDalToCyclonedds(
            d_qos->reader_data_lifecycle.autopurge_nowriter_samples_delay);  // DDS_INFINITY;

    c_qos->reader_data_lifecycle.autopurge_disposed_samples_delay =
        ConvertTimeDurtaitonFromDalToCyclonedds(
            d_qos->reader_data_lifecycle.autopurge_disposed_samples_delay);  // DDS_INFINITY;

    SetDataReaderQosPresent(c_qos);
    return DAL_RETCODE_OK;
}
